package com.brewdroid.db.dao;

import java.util.ArrayList;

import android.content.ContentValues;
import android.database.Cursor;

import com.brewdroid.db.DatabaseHelper;
import com.brewdroid.exception.RecipeNameTakenException;
import com.brewdroid.model.IngredientStep;
import com.brewdroid.model.Recipe;

public class RecipeDAO {
	
	private static final String TABLE="recipe";
	private static final String NULL_COL="description";
	private static final String RECIPE_SELECT_ID="select _id from recipe r where r.name=?";
	private static final String RECIPE_SELECT_ALL="select * from recipe order by name";
	private static final String RECIPE_SELECT_BY_NAME="select * from recipe r where r.name=? order by name";
	
	/**
	 * 
	 * @param db
	 * @param name the name of the recipe to select
	 * @return the entire recipe and its ingredient steps
	 */
	public static Recipe getRecipeFromName(DatabaseHelper db, String name)
	{
		Recipe rec = null;
		Cursor c = db.getReadableDatabase().rawQuery(RECIPE_SELECT_BY_NAME, new String[]{name});
		if(c.moveToFirst())
		{
			rec=new Recipe();
			rec.setAbv(c.getFloat(6));
			rec.setName(c.getString(1));
			rec.setDescription(c.getString(2));
			rec.setStyle(c.getString(3));
			rec.setOriginalGravity(c.getFloat(4));
			rec.setFinalGravity(c.getFloat(5));
			rec.setIngredientList(IngredientStepDAO.getIngredientStepsForRecipe(db, c.getInt(0)));
		}		
		return rec;
	}
	
	/**
	 * 
	 * @param db
	 * @param recipe the recipe to persist to sqlite
	 * This method should be called after a user creates a new recipe for the first time
	 * @throws RecipeNameTakenException 
	 */
	public static void addRecipe(DatabaseHelper db, Recipe recipe) throws RecipeNameTakenException
	{	
		if(recipeNameTaken(db, recipe))
			throw new RecipeNameTakenException("recipe name: "+ recipe.getName() + " already in use.");
		
			
		ContentValues cv  = new ContentValues();
		cv.put("name", recipe.getName());
		cv.put("description", recipe.getDescription());
		cv.put("style",recipe.getStyle());
		cv.put("originalGravity",Float.toString(recipe.getOriginalGravity()));
		cv.put("finalGravity", Float.toString(recipe.getFinalGravity()));
		cv.put("abv", Float.toString(recipe.getAbv()));
		
		long identity=db.getWritableDatabase().insert(TABLE, NULL_COL, cv);
		ArrayList<IngredientStep> ingredients = (ArrayList<IngredientStep>) recipe.getIngredientList();
		
		//if the recipe has ingredientsteps we must add them and than update recipe row
		if(ingredients!=null && ingredients.size()>0)
		{
			for(IngredientStep ingrdient:ingredients)
				addIngredientStepToRecipe(db, ingrdient, (int)identity);
		}
		
	}
	


	/**
	 * 
	 * @param db
	 * @param recipe the recipe that the user has updated and needs updated in sqlite
	 * This method should be called when a user updates any attribute on a recipe, or any attributes on any of 
	 * its ingredientsteps.  It does an update ninja style (deletes the old recipe instance from sqlite, and creates a 
	 * new one) probably not ideal, but it gets the job done.
	 */
	public static void updateRecipe(DatabaseHelper db, Recipe recipe)
	{
		//its not the best answer, but it works.
		//we could have in issue if the delete works but the add were to fail.
		deleteSingleRecipe(db, recipe);
		try {
			addRecipe(db, recipe);
		} catch (RecipeNameTakenException e) {
			
			e.printStackTrace();
		}
	}
	
	/**
	 * 
	 * @param db
	 * @return returns all the recipes and thier ingredientSteps, that are currently in the sqlite db.
	 */
	public static ArrayList<Recipe> getRecipes(DatabaseHelper db)
	{
		ArrayList<Recipe> recipes = new ArrayList<Recipe>();
		Cursor c = db.getReadableDatabase().rawQuery(RECIPE_SELECT_ALL, new String[]{});
		if(c.moveToFirst())
		{
			do
			{
				Recipe rec= new Recipe();
				rec.setAbv(c.getFloat(6));
				rec.setName(c.getString(1));
				rec.setDescription(c.getString(2));
				rec.setStyle(c.getString(3));
				rec.setOriginalGravity(c.getFloat(4));
				rec.setFinalGravity(c.getFloat(5));
				rec.setIngredientList(IngredientStepDAO.getIngredientStepsForRecipe(db, c.getInt(0)));				
				
				recipes.add(rec);
			}while(c.moveToNext());
		}
		return recipes;
	}
	
	/**
	 * 
	 * @param db
	 * deletes all recipes from the DB, probably never want to call this, except if the data gets curropted
	 */
	public static void deleteAll(DatabaseHelper db)
	{
		db.getWritableDatabase().delete(TABLE,null, null);
	}
	
	/**
	 * 
	 * @param db
	 * @param recipe the recipe instance to delete in sqlite
	 * this deletes a single recipe and its child rows in ingredientStep.
	 */
	public static void deleteSingleRecipe(DatabaseHelper db, Recipe recipe)
	{
		//delete child rows in ingredientstep table
		IngredientStepDAO.deleteRecipeSteps(db, getId(db, recipe));
		//delete parent recipe row
		db.getWritableDatabase().delete(TABLE, "_id=?", new String[]{Integer.toString(getId(db, recipe))});
	}
	
	/**
	 * 
	 * @param db
	 * @param recipe the recipe to get the id of
	 * @return the _id field value in the recipe table, for the recipe passed in.
	 */
	public static int getId(DatabaseHelper db, Recipe recipe)
	{
		int id=0;
		Cursor c = db.getReadableDatabase().rawQuery(RECIPE_SELECT_ID, new String[]{	recipe.getName()
																					});
		if(c.moveToFirst())
			id=c.getInt(0);
		
		return id;
		
	}
	
	
	private static boolean recipeNameTaken(DatabaseHelper db, Recipe recipe) 
	{
		Recipe r = getRecipeFromName(db, recipe.getName());
		return r==null? false:true;
	}
	
	/**
	 * 
	 * @param db
	 * @param inStep the ingredientstep to associate with the recipeId
	 * @param recipeId the id of the recipe the ingredientstep should be assigned to.
	 * this is an private method and is used in this class when adding a recipe and updating one.
	 */
	private static void addIngredientStepToRecipe(DatabaseHelper db, IngredientStep inStep, int recipeId)
	{
		IngredientStepDAO.addToRecipe(db, inStep, recipeId);
		
		
	}
	
	/**
	 * 
	 * @param db
	 * @param inStep the ingredientstep to associate with the recipeId
	 * @param recipe the recipe the ingredientstep should be assigned to.
	 * this is an private method and is used in this class when adding a recipe and updating one.
	 */ 
	private static void addIngredientStepToRecipe(DatabaseHelper db, IngredientStep inStep, Recipe recipe)
	{
		IngredientStepDAO.addToRecipe(db, inStep, getId(db, recipe));
	}
	
	
	
	
	

}
